#include <stdio.h>
#include <modbus.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/types.h>
#include "msg_queue_peer.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/msg.h>
#include <stdlib.h>
#include "cJSON.h"
#include "kernel_list.h"
#include "shmem.h" //共享内存

//消息队列
struct msg
{
    long type;
    int key;
    char val[32];
};

struct mb_node
{
    int key;        //唯一键值
    char name[128]; //数据点名称
    int type;       //数据点类型
    int addr;
};

struct mb_node_list
{
    struct mb_node node;
    struct list_head list;
};

//共享内存内数据的结构体
union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};

struct list_head head;
char buf[32];
struct mb_node_list *tmp;
struct list_head *pos;
void *gather(void *arg)
{
    uint16_t data[1024] = {};
    uint16_t data1[1024] = {};
    uint16_t data2[1024] = {};
    uint8_t dest[1024] = {};
    uint8_t dest2[1024] = {};
    //（1）共享内存初始化
    struct shm_param para;
    int ret = shm_init(&para, "shm", 1024); //结构体  共享内存文件名字 共享内存大小
    if (ret < 0)
    {
        perror("shm_init err");
        //return -1;
    }
    //（2）获取共享内存地址
    void *addr = shm_getaddr(&para);

    if (addr == NULL)
    {
        printf("shm get addr err\n");
    }
    // int *p = NULL;
    // p = addr;
    // printf("Address=%p\n", p);
    int *num = (int*)addr;
    *num = 6;
    printf("num=%d\n", *num);

    struct std_node *add = (struct std_node *)(addr + sizeof(int)); //书写内容的共享内存
    
    printf("type:%d",add->type);
    printf("key:%d",add->key);

    //数据处理
    modbus_t *mod = (modbus_t *)arg;
     
    while (1)
    {
        //一直进行读取
        sleep(3);
        list_for_each(pos, &head)
        {
            tmp = list_entry(pos, struct mb_node_list, list);
            //环境温度
            if (tmp->node.key == 101)
            {
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data);
                printf("环境温度寄存器= %u 地址=%d\n", data[0], tmp->node.addr - 1 - 30000);
            }
            //环境湿度
            else if (tmp->node.key == 102)
            {
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data + 2);
                printf("环境湿度寄存器= %u 地址=%d\n", data[2], tmp->node.addr - 1 - 30000);
            }
            //光照强度
            else if (tmp->node.key == 103)
            {
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data + 4);
                printf("光照强度寄存器= %u 地址=%d\n", data[4], tmp->node.addr - 1 - 30000);
                // modbus_read_bits(mod, tmp->node.addr - 1, 2, dest);
                // printf("空调开关= %u 地址=%#x\n ", dest[0], tmp->node.addr - 1);
            }
            //空调的温度,
            //读取保持寄存器(功能码 0x3)
            //土壤湿度
            else if (tmp->node.key == 104)
            {
                // modbus_read_registers(mod, tmp->node.addr - 1 - 40000 + 4, 2, data + 4);
                // printf("空调温度寄存器= %u 地址=%d\n", data[4], tmp->node.addr - 1 - 40000 + 4);
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data + 6);
                printf("土壤湿度寄存器= %u 地址=%d\n", data[6], tmp->node.addr - 1 - 30000);
            }
            //二氧化碳
            else if (tmp->node.key == 105)
            {
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data + 8);
                printf("土壤湿度寄存器= %u 地址=%d\n", data[8], tmp->node.addr - 1 - 30000);
                // modbus_read_registers(mod, tmp->node.addr - 30005 + 8, 2, data + 8);
                // printf("光照寄存器= %u 地址=%d\n", data[8], tmp->node.addr - 30005 + 8);
            }
            //氧气
            else if (tmp->node.key == 106)
            {
                // modbus_read_bits(mod, tmp->node.addr - 4 + 1, 2, dest + 1);
                // printf("遮光板开关= %u   地址=%#x\n", dest[1], tmp->node.addr - 4 + 1);
                modbus_read_registers(mod, tmp->node.addr - 1 - 30000, 2, data + 10);
                printf("土壤湿度寄存器= %u 地址=%d\n", data[10], tmp->node.addr - 1 - 30000);

            }

        }
        printf("num=%d\n", *num);
        //更新新旧值
        for (int i = 7; i < 13; i++)
        {
            add[i].key = (101-7+i);
            
            if (add[i].key == 101) //室外温度
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data);

                printf("Temperature sensor=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("Temperature sensor err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 102) //室外湿度
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data + 2);
                printf("Humi sensor=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning switch err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 103) //空调开关
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data + 4);
                printf("light intensity=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning switch err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 104) //空调温度
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data + 6);
                printf("soil humi sensor=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].type = 3;
                    add[i].ret = -1;
                    printf("air Temperature sensor err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 105) //光照强度
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data + 8);
                printf("光照=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning switch err:=%d\n", add[i].ret);
                }
            }
            else if (add[i].key == 106) //遮光板
            {
                add[i].type = 3;
                add[i].old_val.f_val = add[i].new_val.f_val;
                add[i].new_val.f_val = modbus_get_float_dcba(data + 10);
                printf("遮光板=%.2f\n", add[i].new_val.f_val);
                if (add[i].new_val.f_val != 0)
                {
                    add[i].ret = 0;
                }
                else
                {
                    add[i].ret = -1;
                    printf("air conditioning switch err:=%d\n", add[i].ret);
                }
            }
        }

        
        for (int i = 7; i < 13; i++)
        {
            if (add[i].key == 101)
            {
                printf("type=%d key=%d new_val=%.2f old_val=%.2f\n",add[i].type, add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            else if (add[i].key == 102)
            {
                printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            else if (add[i].key == 103)
            {
                printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            else if (add[i].key == 104)
            {
                printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            else if (add[i].key == 105)
            {
                printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            else if (add[i].key == 106)
            {
                printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            }
            // else if (add[i].key == 107)
            // {
            //     printf("key=%d new_val=%d old_val=%d\n", add[i].key, add[i].new_val.i_val, add[i].old_val.i_val);
            // }
            // else if (add[i].key == 108)
            // {
            //     printf("key=%d new_val=%.2f old_val=%.2f\n", add[i].key, add[i].new_val.f_val, add[i].old_val.f_val);
            // }
        }
        sleep(1);
    }
    shm_del(&para);
    pthread_exit(NULL);
}
void *ctrl(void *arg)
{
    printf("hello1\n");
    modbus_t *mod = (modbus_t *)arg;
    struct msg msg;
    msg.type = 222;
    printf("%s\n",msg.val);
    while (1)
    {    
        if (msg_queue_recv("msg", &msg, sizeof(msg), 222, 0)> 0)// 
            {
                printf("key=%d\n", msg.key); //打印此时的key值
                printf("val=%s\n", msg.val); //打印此时的value值
                list_for_each(pos, &head)
                {
                    // printf("world\n");
                    tmp = list_entry(pos, struct mb_node_list, list);
                    if (msg.key == tmp->node.key)
                    {
                        if (msg.key == 103) //空调开关
                        {
                            int num = atoi(msg.val);
                            modbus_write_bit(mod, tmp->node.addr - 1, num);
                        }
                        else if (msg.key == 104) //空调温度控制
                        {
                            uint16_t buf[4];
                            float value = atof(msg.val);
                            modbus_set_float_dcba(value, buf);
                            modbus_write_registers(mod, tmp->node.addr - 1 - 40000 + 4, 2, buf);
                        }
                        else if (tmp->node.key == 106)
                        {
                            int num = atoi(msg.val);
                            modbus_write_bit(mod, tmp->node.addr - 4 + 1, num);
                        }
                    }
                }
            }
    }
    pthread_exit(NULL);
    pause();
}

int main(int argc, char const *argv[])
{
    //内核链表
    //(1)内核链表初始化

    INIT_LIST_HEAD(&head);

    //一、解析点表：1.确定需要哪个设备  2.确定采集还是控制
    FILE *fp;
    char buf[65536] = "";
    // /home/hq/mnt/config/point_table.json
    fp = fopen("./node.json", "r"); //打开
    if (fp == NULL)
    {
        perror("fopen err");
    }
    fread(buf, 65536, 1, fp); //读取，放到缓冲区
    printf("buf=%s\n", buf);
    cJSON *root = cJSON_Parse(buf);
    cJSON *version = cJSON_GetObjectItem(root, "version");
    cJSON *report = cJSON_GetObjectItem(root, "report");
    cJSON *type = cJSON_GetObjectItem(report, "type");
    // printf("%s:%d\n", type->string, type->valueint);
    cJSON *period = cJSON_GetObjectItem(report, "period");
    //获取ip+端口号
    cJSON *mb_dev = cJSON_GetObjectItem(root, "mb_dev");
    cJSON *addr = cJSON_GetObjectItem(mb_dev, "addr");
    cJSON *por = cJSON_GetObjectItem(mb_dev, "port");
    char ip[32] = "";
    int port = por->valueint;
    strcpy(ip, addr->valuestring);
    printf("ip=%s,port=%d\n", ip, port);

    cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    cJSON *name = cJSON_GetObjectItem(modbus, "name");
    cJSON *data = cJSON_GetObjectItem(modbus, "data");
    int array_len = cJSON_GetArraySize(data);
    cJSON *datachild = data->child;
    printf("len=%d\n", array_len);
    for (int i = 0; i < array_len; i++)
    {
        cJSON *arr = cJSON_GetArrayItem(data, i);
        struct mb_node_list *array = (struct mb_node_list *)malloc(sizeof(struct mb_node_list));
        cJSON *key = cJSON_GetObjectItem(arr, "key");
        //printf("%s=%d\n", key->string, key->valueint);
        cJSON *name = cJSON_GetObjectItem(arr, "name");
        //printf("%s=%s\n", name->string, name->valuestring);
        cJSON *addr = cJSON_GetObjectItem(arr, "addr");
        //printf("%s=%d\n", addr->string, addr->valueint);
        cJSON *type = cJSON_GetObjectItem(arr, "type");
        //printf("%s=%d\n", type->string, type->valueint);
        array->node.key = key->valueint;
        array->node.addr = addr->valueint;
        list_add(&array->list, &head); //添加到内核链表中去
        datachild = datachild->next;
        printf("\n");
    }
    /* 测试放入循环链表情况 //4.遍历循环
    struct list_head *pos;
    struct mb_node_list *tmp;
    list_for_each(pos, &head)
    {
        tmp = list_entry(pos, struct mb_node_list, list);
        printf("key=%d name=%s addr=%d type=%d\n", tmp->node.key, tmp->node.name, tmp->node.addr, tmp->node.type);
    }*/

    //二、创建子线程分别进行采集和控制
    pthread_t tid1, tid2;
    //1.创建实例
    modbus_t *mod = modbus_new_tcp(ip, port);
    if (NULL == mod)
    {
        perror("err");
        return -1;
    }
    //2.设置从机
    int n = modbus_set_slave(mod, 1);
    //3.建立连接
    modbus_connect(mod);
    if (pthread_create(&tid1, NULL, gather, mod) != 0)
    {
        perror("create thread1 err");
        return -1;
    }
    if (pthread_create(&tid2, NULL, ctrl, mod) != 0)
    {
        perror("create thread2 err");
        return -1;
    }
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    //5.关闭套接字
    modbus_close(mod);
    //6.释放实例
    modbus_free(mod);
    return 0;
}
